package com.kly.user.rulePolicy;

import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.exception.common.ApplicationException;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.api.client.util.Lists;
import com.kly.user.db.dao.TRuleHistoryLogDao;
import com.kly.user.db.entity.TRuleHistoryLogEntity;
import com.kly.user.rulePolicy.enums.DecisionResultEnum;
import com.kly.user.rulePolicy.enums.PolicyComposeEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 决策处理类
 * @author linqu
 */
@Service
public class DecisionAPI {

    public static final Log logger = LogFactory.getLog(DecisionAPI.class);


    @Resource
    ExecutePolicyService executePolicyService;
    @Resource
    TRuleHistoryLogDao ruleHistoryLogDao;
    @Resource
    RedisClient redisClient;
    /**
     * who like me下发策略
     */
    private static final String WLM_POLICY = "1";
    /**
     * likes back策略
     */
    private static final String LIKES_BACK_POLICY = "2";

    public PolicySet decisionResult(DecisionVO decisionVo) {

        logger.info("规则执行开始：{}", JSONObject.toJSONString(decisionVo));
        List<Column> columns = decisionVo.getColumns();


        // 变量有效性校验
        columnListVerify(columns);
        PolicySet policySet = null;
        try {
            policySet = processPolicySet(buildPolicySet(decisionVo.getColumns(), decisionVo.getPolicyId()));
        } catch (Exception e) {
            logger.error("规则执行失败:{}", JSONObject.toJSONString(decisionVo), e);
            policySet = new PolicySet();
            policySet.setPolicySetResult(DecisionResultEnum.UNKNOWN.getType());
        }

        // 日志留存
        final TRuleHistoryLogEntity result = makeDecisionCallHistory(decisionVo, policySet);
        policySet.setResult(result);
        return policySet;

    }

    private TRuleHistoryLogEntity makeDecisionCallHistory(DecisionVO decisionVo, PolicySet policySet) {
        TRuleHistoryLogEntity entity = new TRuleHistoryLogEntity();
        try {
            entity.setUserCode(decisionVo.getUserCode());
            entity.setApiReqId(decisionVo.getApiReqId());
            entity.setPolicyName(policySet.getPolicySetName());
            entity.setResultType(policySet.getPolicySetResult());
            entity.setDecisionResult(JSONObject.toJSONString(policySet));
//            entity.setPolicyDetail(policySetStr);
//            entity.setRequestParams(JSONObject.toJSONString(decisionVo));
            ruleHistoryLogDao.insert(entity);
            return entity;
        } catch (Exception e) {
            logger.error("DecisionCallFailed, ruleHistoryLogEntity={}", JSONObject.toJSONString(entity), e);
            throw new ApplicationException("DecisionCallFailed");
        }
    }

    public PolicySet processPolicySet(PolicySet policySet) {
        logger.info("规则策略及完整参数: {}", JSONObject.toJSONString(policySet));
        // 获取PolicySet采用的匹配类型
        PolicyComposeEnum policyCompose = PolicyComposeEnum.transformByName(policySet.getPolicyCompose());
        if (Objects.isNull(policyCompose)) {
            throw new ApplicationException("未设置匹配类型。");
        }

        // 获取策略集合
        List<Policy> policySetList = policySet.getPolicyList();

        // 首次匹配规则执行逻辑：WLM下发规则采用首次匹配
        final List<Policy> policyResults = policySetList.stream()
                .map(p -> executePolicyService.processPolicy(p)).collect(Collectors.toList());

        boolean policySetResult = false;
        if (policyCompose.equals(PolicyComposeEnum.FIRST)) {
            policySetResult = policyResults.stream().anyMatch(o -> o.getPolicyResult().equals(DecisionResultEnum.PASS.getType()));
        }
        if (policyCompose.equals(PolicyComposeEnum.WORST)) {
            policySetResult = policyResults.stream().allMatch(o -> o.getPolicyResult().equals(DecisionResultEnum.PASS.getType()));
        }

        if (policySetResult) {
            policySet.setPolicySetResult(DecisionResultEnum.PASS.getType());
        } else {
            policySet.setPolicySetResult(DecisionResultEnum.REJECT.getType());
        }


        return policySet;
    }

    private List<Column> columnListVerify(List<Column> columnList) {

        // TODO: 2023/6/23 检查传入的变量是否与nacos里配置的一致
        return columnList;

    }

    @NacosValue(value = "${user.wlm.policy_v_1.0}", autoRefreshed = true)
    private String policySetStr;
    @NacosValue(value = "${user.wlm.likesBack.policy_v_1.0}", autoRefreshed = true)
    private String policyLikesBackSetStr;
    /**
     * 规则配置文件
     */
    public PolicySet buildPolicySet(List<Column> columnList, String decisionId) {
        String policy = null;
        if (WLM_POLICY.equalsIgnoreCase(decisionId)) {
            policy = policySetStr;
        } else if (LIKES_BACK_POLICY.equalsIgnoreCase(decisionId)) {
            policy = policyLikesBackSetStr;
        }

        //入参变量
        if (StringUtils.isBlank(policy)) {
            throw new ApplicationException("未配置策略");
        }

        for (Column column : columnList) {
            policy = policy.replaceAll("#" + column.getColumnCode() + "#", String.valueOf(column.getColumnValue()));
        }

        return JSONObject.parseObject(policy, PolicySet.class);
    }

    public static void main(String[] args) {
        DecisionAPI api = new DecisionAPI();
        DecisionVO decisionVO = DecisionVO.builder().build();

        List<Column> columns = Lists.newArrayList();

        final Column column1 = Column.builder().columnCode("var_wlm_like_num").columnType("INT").columnValue(1).build();
        columns.add(column1);
        final Column column2 = Column.builder().columnCode("var_register_time").columnType("INT").columnValue(1).build();
        columns.add(column2);

        decisionVO.setColumns(columns);

        final PolicySet policySet = api.decisionResult(decisionVO);
        System.out.println(JSONObject.toJSONString(policySet));


    }

}
